#include "route_trainer_manager.h"
#include "static_functions.h"
#include "positionmanager.h"
#include "route_train_dialog.h"
#include <QFile>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <Windows.h>
#include <QMessageBox>
#include <QDebug>
#include <QDateTime>
#include <math.h>


RouteTrainerManager::RouteTrainerManager() {

}

bool RouteTrainerManager::loadRoutePositions()
{
    QFile file("route_pos.json");
    if (!file.open(QIODevice::ReadOnly)) {
        QMessageBox::critical(nullptr, "错误", "打开文件 route_pos.json 失败");
        return false;
    }

    QByteArray jsonData = file.readAll();
    file.close();

    QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonData);
    if (jsonDoc.isNull()) {
        QMessageBox::critical(nullptr, "错误", "文件 route_pos.json 不是合法的json格式, 请恢复这个文件");
        return false;
    }
    QJsonArray root = jsonDoc.array();

    positionInfoList.clear();
    for (int i=0; i<root.size(); ++i) {
        positionInfoList.append(root.at(i).toObject());
    }

    return true;
}

int RouteTrainerManager::startTrain(PositionManager* positionManager)
{
    // 初始化
    this->positionManager = positionManager;

    // 加载route坐标列表
    loadRoutePositions();

    isRoleStartRunning = false;
    lastNearestPosIdx = -1;
    lastClimbOrStopStartTimeMS = 0;
    isLastRoleInClimbOrStop = false;
    climbOrStopSegmentList.clear();
    for (int i=0; i<positionInfoList.length(); ++i) {
        QJsonObject& positionInfo = positionInfoList[i];
        positionInfo.remove("minDistance");
        positionInfo.remove("minDistanceTimeMS");
    }


    // 创建监听线程
    isTrackThreadRun = true;
    auto threadTest = std::function<void ()> ([&]() {
        while (isTrackThreadRun) {
            if (trackPosition() >= 0) {
                QList<RouteTrainDisplayInfo*> * rtdiList = resolveRouteTrainDisplayInfoList(false);
                StaticFunctions::noticeDisplayRouteTrainResult(rtdiList, false);
            }
            trackThread->usleep(100*1000);
        }
    });
    trackThread = QThread::create(threadTest);
    trackThread->start();
}
// 其他线程停止监听线程
QList<RouteTrainDisplayInfo*> * RouteTrainerManager::endTrainByOtherThread(bool needDisplayInfo)
{
    isTrackThreadRun = false;
    if (trackThread != NULL) {
        trackThread->terminate();
        trackThread = NULL;
    }

    if (needDisplayInfo)
        return resolveRouteTrainDisplayInfoList(true);
    else
        return NULL;
}

// 返回值: <= -2 运行错误;  -1 没有变化;  0 从起点出发;  > 0 到达一个新的节点
int RouteTrainerManager::trackPosition()
{
    // 获取当前时间
    const QDateTime currentDateTime = QDateTime::currentDateTime();
    const long long currentTimeMS = currentDateTime.toMSecsSinceEpoch();   // 将当前时间转为时间戳


    // 找到距离最近的点
    int nearestPosIdx = -1;
    double nearestPosDis = 10000000;
    if (!isRoleStartRunning) {
        // 根据速度矢量判断是否启动
        const Position* velocity = positionManager->trackRoleVelocityAndReturn();
        if (NULL != velocity) {
            if (velocity->x != 0 || velocity->y != 0) {
                nearestPosIdx = 0;
                nearestPosDis = 0;
            }
            delete velocity;
        }
        if (nearestPosIdx != 0) return -1;
    } else {
        for (int i=0; i<positionInfoList.length(); ++i)
        {
            QJsonObject& positionInfo = positionInfoList[i];
            double disRadius = positionInfo["disRadius"].toDouble();

            // 当前坐标
            const Position* position = positionManager->trackRolePositionAndReturn();
            if (NULL == position) return -2;
            const double x = position->x;
            const double y = position->y;
            const double z = position->z;
            delete position;

            double xDistance = positionInfo.value("x").toDouble() - x;
            double yDistance = positionInfo.value("y").toDouble() - y;
            double zDistance = positionInfo.value("z").toDouble() - z;
            double distance = sqrt(xDistance*xDistance + yDistance*yDistance + zDistance*zDistance);
            if (distance <= disRadius) {
                nearestPosIdx = i;
                nearestPosDis = distance;
                break;
            }
        }
    }

    // 在点附近
    bool reachNewSegment = false;
    if (nearestPosIdx == 0) {
        if (lastNearestPosIdx != 0) {
            // 初始化
            isRoleStartRunning = true;
            lastClimbOrStopStartTimeMS = currentTimeMS;
            isLastRoleInClimbOrStop = false;
            climbOrStopSegmentList.clear();
            for (int i=0; i<positionInfoList.length(); ++i) {
                QJsonObject& positionInfo = positionInfoList[i];
                positionInfo.remove("minDistance");
                positionInfo.remove("minDistanceTimeMS");
            }

            // 记录起点
            QJsonObject& positionInfo = positionInfoList[0];
            positionInfo["minDistance"] = 0;
            positionInfo["minDistanceTimeMS"] = QString::number(currentTimeMS, 16);

            // 游戏开始 跑
            reachNewSegment = true;
        }
    } else if (nearestPosIdx > 0) {
        // 可能先跑到后面的节点, 再跑到前面的节点. 这个时候清除后面节点的信息
        for (int i=nearestPosIdx+1; i<positionInfoList.length(); ++i) {
            QJsonObject& positionInfo = positionInfoList[i];
            positionInfo.remove("minDistance");
            positionInfo.remove("minDistanceTimeMS");
        }

        QJsonObject& positionInfo = positionInfoList[nearestPosIdx];
        if (!positionInfo.contains("minDistance")) {
            positionInfo["minDistance"] = nearestPosDis;
            positionInfo["minDistanceTimeMS"] = QString::number(currentTimeMS, 16);

            // 进入新的分段
            reachNewSegment = true;
        } else {
            const double lastMinDistance = positionInfo["minDistance"].toDouble();
            // 更新 最近距离和到达时间
            if (nearestPosDis < lastMinDistance) {
                positionInfo["minDistance"] = nearestPosDis;
                positionInfo["minDistanceTimeMS"] = QString::number(currentTimeMS, 16);
            }
        }
    }


    // 判断人物是否处于 攀爬或者静止状态
    if (isRoleStartRunning) {
        const bool isRoleClimbOrStop = positionManager->isRoleClimbOrStop();
        if (isLastRoleInClimbOrStop) {
            if (!isRoleClimbOrStop || nearestPosIdx == positionInfoList.length()-1) {   // 终止了静止状态或者游戏结束
                TimePeriod timePeriod;
                timePeriod.startTimeMs = lastClimbOrStopStartTimeMS;
                timePeriod.endTimeMs = currentTimeMS;
                climbOrStopSegmentList.append(timePeriod);
            }
        } else {
            if (isRoleClimbOrStop) {
                // 新的开始
                lastClimbOrStopStartTimeMS = currentTimeMS;
            }
        }
        isLastRoleInClimbOrStop = isRoleClimbOrStop;
    }


    if (nearestPosIdx >= 0) {
        lastNearestPosIdx = nearestPosIdx;
    }


    if (reachNewSegment)
        return nearestPosIdx;
    else
        return -1;
}

QList<RouteTrainDisplayInfo*>* RouteTrainerManager::resolveRouteTrainDisplayInfoList(bool ended)
{
    if (!isRoleStartRunning) return NULL;

    QList<RouteTrainDisplayInfo*>* result = new QList<RouteTrainDisplayInfo*>();

    bool toLongLongOk = false;

    int lastReachIdx = 0;
    long long startRunTimeMS = positionInfoList[0]["minDistanceTimeMS"].toString().toLongLong(&toLongLongOk, 16);
    for (int i=1; i<positionInfoList.length(); ++i) {
        const QJsonObject& positionInfo = positionInfoList[i];
        if (!positionInfo.contains("minDistance")) continue;

        const QJsonObject& lastReachPosInfo = positionInfoList[lastReachIdx];


        RouteTrainDisplayInfo* info = new RouteTrainDisplayInfo();
        info->startPosX = lastReachPosInfo["x"].toDouble();
        info->startPosY = lastReachPosInfo["y"].toDouble();
        info->startPosZ = lastReachPosInfo["x"].toDouble();
        info->startPosName = lastReachPosInfo["name"].toString();
        info->reachStartPosTimeMS = lastReachPosInfo["minDistanceTimeMS"].toString().toLongLong(&toLongLongOk, 16);

        info->endPosX = positionInfo["x"].toDouble();
        info->endPosY = positionInfo["y"].toDouble();
        info->endPosZ = positionInfo["x"].toDouble();
        info->endPosName = positionInfo["name"].toString();
        info->reachEndPosTimeMS = positionInfo["minDistanceTimeMS"].toString().toLongLong(&toLongLongOk, 16);

        info->startEndInter = i - lastReachIdx;

        info->reachEndTimeStr = StaticFunctions::spendMSToString(info->reachEndPosTimeMS - startRunTimeMS);
        info->spendTimeStr = StaticFunctions::spendMSToString(info->reachEndPosTimeMS - info->reachStartPosTimeMS);

        info->climbOrStopTimeMS = 0;


        result->append(info);

        lastReachIdx = i;
    }

    // 根据时间计算 攀爬或者静止 属于哪一段
    int lastRouteIdx = 0;
    for (int climbOrStopIdx=0; climbOrStopIdx<climbOrStopSegmentList.length(); ++climbOrStopIdx) {
        const TimePeriod timePeriod = climbOrStopSegmentList[climbOrStopIdx];
        long long startTimeMs = timePeriod.startTimeMs;
        long long endTimeMs = timePeriod.endTimeMs;
        for (int i=lastRouteIdx; i<result->length(); ++i) {
            RouteTrainDisplayInfo* info = result->at(i);
            if (info->reachStartPosTimeMS <= startTimeMs && startTimeMs <= info->reachEndPosTimeMS) {
                if (info->reachStartPosTimeMS <= endTimeMs && endTimeMs <= info->reachEndPosTimeMS) {
                    info->climbOrStopTimeMS = info->climbOrStopTimeMS + (endTimeMs-startTimeMs);
                    break;
                } else {
                    info->climbOrStopTimeMS = info->climbOrStopTimeMS + (info->reachEndPosTimeMS-startTimeMs);
                    startTimeMs = info->reachEndPosTimeMS;
                }
            }
        }
    }

    return result;
}
